using System;
using System.Collections;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace stsdev {

  public class ManifestBuilder {

    private const string nsSP = "http://schemas.microsoft.com/sharepoint/";

    public static void Create(string FilePath, bool AssemblyDeployment) {
      Create(FilePath, AssemblyDeployment, SolutionBuilder.ResetWebServer);
    }

    public static void Create(string FilePath, bool AssemblyDeployment, bool IISRESET) {

      StreamWriter manifestStream = new StreamWriter(FilePath);
      XmlWriterSettings settings = new XmlWriterSettings();
      settings.Encoding = Encoding.UTF8;
      settings.Indent = true;
      settings.NewLineOnAttributes = false;
      settings.NewLineHandling = NewLineHandling.None;
      XmlWriter writer = XmlWriter.Create(manifestStream, settings);
      writer.WriteStartDocument();

      writer.WriteComment("Manifest created STSDEV utility at " + DateTime.Now.ToString());
      writer.WriteStartElement("Solution", nsSP);
      // add solution ID
      writer.WriteAttributeString("SolutionId", SolutionBuilder.SolutionId);
      writer.WriteAttributeString("ResetWebServer", IISRESET.ToString());

      if (Directory.Exists(Globals.FeaturesFolder)) {
        // write feature manifests
        writer.WriteComment("Feature Manifest files");
        writer.WriteStartElement("FeatureManifests");
        // write FEATURE Files
        foreach (string directory in Directory.GetDirectories(Globals.FeaturesFolder)) {
          WriteFeatureManifestFile(writer, directory.Substring((Globals.FeaturesFolder + @"\").Length) + @"\feature.xml");
        }
        writer.WriteEndElement(); // </FeatureManifest>
      }

      if (Directory.Exists(Globals.TemplatesFolder)) {
        // write TEMPLATE Files
        writer.WriteComment("TEMPLATE files");
        writer.WriteStartElement("TemplateFiles");
        WriteTemplateFiles(writer);
        writer.WriteEndElement(); // </TemplateFiles>
      }

      if (Directory.Exists(Globals.IsapiFolder) || Directory.Exists(Globals.ResourcesFolder)) {
        // write Root Files
        writer.WriteComment("Root files");
        writer.WriteStartElement("RootFiles");
        WriteRootFiles(writer);
        writer.WriteEndElement(); // </RootFiles>
      }

      if (SolutionBuilder.AssemblyDeployment) {
        // write Assembly Files
        writer.WriteComment("Assembly files");
        writer.WriteStartElement("Assemblies");
        foreach (SolutionAssembly asm in SolutionBuilder.Assemblies) {
          WriteAssembly(writer, asm);
        }
        writer.WriteEndElement(); // </Assemblies>
      }

      if ( (SolutionBuilder.CasPermissions) && 
           (SolutionBuilder.CasPermissionsNode!=null)  ){
        writer.WriteComment("Code Access Security Permissions");
        WriteCasPermissions(writer);
      }

      if (SolutionBuilder.DwpFilesNode != null)
      {
          writer.WriteComment("NonFeature Web Parts");
          WriteDwpFiles(writer);
      }

      writer.WriteEndElement(); // </Solution>
      writer.WriteEndDocument();
      writer.Close();
      manifestStream.Close();

    }

    private static void WriteDwpFiles(XmlWriter writer)
    {
        if (SolutionBuilder.DwpFilesNode == null)
        {
            Console.WriteLine("Solution has no webpart Files in SolutionConfig.xml");
            return;
        }
        writer.WriteStartElement("DwpFiles");
        foreach (XmlNode child in SolutionBuilder.DwpFilesNode)
        {
            writer.WriteStartElement("DwpFile");
            foreach (XmlAttribute attr in child.Attributes)
            {
                writer.WriteAttributeString(attr.Name, attr.Value);
            }
            writer.WriteEndElement();
        }
        writer.WriteEndElement();
    } 

    static private void WriteFeatureManifestFile(XmlWriter writer, string path) {
      writer.WriteStartElement("FeatureManifest");
      writer.WriteAttributeString("Location", path);
      writer.WriteEndElement();
    }

    static void WriteTemplateFiles(XmlWriter writer) {
      EnumerateTemplateDirectory(writer, Globals.TemplatesFolder);
    }

    static void EnumerateTemplateDirectory(XmlWriter writer, string path) {

      foreach (string file in Directory.GetFiles(path)) {
        if (!file.Contains("FEATURES")) {
          writer.WriteStartElement("TemplateFile");
          writer.WriteAttributeString("Location", file.Substring((Globals.TemplatesFolder + @"\").Length));
          writer.WriteEndElement();
        }
      }

      foreach (string folder in Directory.GetDirectories(path)) {
        if (!folder.Contains("FEATURES")) {
          EnumerateTemplateDirectory(writer, folder);
        }
      }
    }

    static void WriteRootFiles(XmlWriter writer) {
      EnumerateRootFilesDirectory(writer, Globals.RootFilesFolder);
    }

    static void EnumerateRootFilesDirectory(XmlWriter writer, string path) {
      foreach (string file in Directory.GetFiles(path)) {
        if (!file.Contains("TEMPLATE")) {
          writer.WriteStartElement("RootFile");
          writer.WriteAttributeString("Location", file.Substring((Globals.RootFilesFolder + @"\").Length));
          writer.WriteEndElement();
        }
      }

      foreach (string folder in Directory.GetDirectories(path)) {
        if (!folder.Contains("TEMPLATE")) {
          EnumerateRootFilesDirectory(writer, folder);
        }
      }
    }

    static void WriteAssembly(XmlWriter writer, SolutionAssembly asm) {
      writer.WriteStartElement("Assembly");
      writer.WriteStartAttribute("Location");
      writer.WriteValue(asm.Location);
      writer.WriteEndAttribute();
      writer.WriteStartAttribute("DeploymentTarget");
      writer.WriteValue(asm.DeploymentTarget);
      writer.WriteEndAttribute();
      if (SolutionBuilder.SafeControlSettings &&
          asm.SafeControlEntries.Count > 0) {
        writer.WriteStartElement("SafeControls");
        foreach (SolutionSafeControlEntry entry in asm.SafeControlEntries) {
          writer.WriteStartElement("SafeControl");
          writer.WriteStartAttribute("Assembly");
          writer.WriteValue(entry.Assembly);
          writer.WriteEndAttribute();
          writer.WriteStartAttribute("Namespace");
          writer.WriteValue(entry.Namespace);
          writer.WriteEndAttribute();
          writer.WriteStartAttribute("TypeName");
          writer.WriteValue(entry.TypeName);
          writer.WriteEndAttribute();
          writer.WriteStartAttribute("Safe");
          writer.WriteValue(entry.Safe);
          writer.WriteEndAttribute();
          writer.WriteEndElement(); // </SafeControl>
        }
        writer.WriteEndElement();
      }
      writer.WriteEndElement();
    }

    static void WriteCasPermissions(XmlWriter writer) {
      if (SolutionBuilder.CasPermissionsNode == null) {
        Console.WriteLine("Solution has no CAS Permissions in SolutionConfig.xml");
        return;
      }
      writer.WriteStartElement("CodeAccessSecurity");
      writer.WriteStartElement("PolicyItem");
      writer.WriteStartElement("PermissionSet");
      writer.WriteAttributeString("class", "NamedPermissionSet");
      writer.WriteAttributeString("version", "1");
      writer.WriteAttributeString("Name", SolutionBuilder.TargetName);
      // write out each CAS permission as an IPermission element
      foreach (XmlNode child in SolutionBuilder.CasPermissionsNode) {
        writer.WriteStartElement("IPermission");
        foreach (XmlAttribute attr in child.Attributes) {
          writer.WriteAttributeString(attr.Name, attr.Value);
        }
        writer.WriteEndElement(); // </IPermission>
      }
      writer.WriteEndElement(); // </PermissionSet>

      writer.WriteStartElement("Assemblies");
      writer.WriteStartElement("Assembly");
      writer.WriteAttributeString("Name", SolutionBuilder.TargetName);
      writer.WriteEndElement(); // </Assembly>
      writer.WriteEndElement(); // </Assemblies>
      writer.WriteEndElement(); // </PolicyItem>
      writer.WriteEndElement(); // </CodeAccessSecurity>      
    }

  }

}
